{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 问题：Django 重定向你是如何实现的？用的什么状态码？\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "面试官想从这道题中考察面试人什么？\n",
    "重定向在 WEB 开发中必然会碰到的，所以你必须知道在 Django 中它是怎么实现的。\n",
    "\n",
    "答案\n",
    "重定向的实现方式：\n",
    "\n",
    "调用函数 redirect 和 reverse；\n",
    "从视图返回 HttpResponseRedirect 或 HttpResponsePermanentRedirect 实例；\n",
    "RedirectView 视图类；\n",
    "状态码：302，301。\n",
    "拓展\n",
    "重定向是什么？就是将用户从一个 URL 自动转到另外一个。\n",
    "\n",
    "在 Django 中，可以通过从视图返回 HttpResponseRedirect 或 HttpResponsePermanentRedirect 实例来将用户重定向到另一个 URL。还有最简单的方法就是使用 django.shortcuts 模块中的 redirect() 函数。参照下面这个例子：\n",
    "\n",
    "# views.py\n",
    "from django.shortcuts import redirect, render\n",
    "\n",
    "def hello_view(reques):\n",
    "    return render(\"hello.html\")\n",
    "\n",
    "# 方法一\n",
    "def redirect_view(request):\n",
    "    response = redirect('/redirect-success/') # 这里跳转到另外一个URL，比如`http://mywebsite.com/redirect-success/`，然后找到相应的URL所对应的视图逻辑再执行\n",
    "    return response\n",
    "\n",
    "def redirect_success_view(request):\n",
    "    return render(\"success.html\") # 渲染相应的模板\n",
    "# urls.py\n",
    "from django.urls import path\n",
    "\n",
    "from . import views\n",
    "\n",
    "urlpatterns = [\n",
    "    path('/hello/', veiw.hello_view),\n",
    "    path('/redirect/', veiw.redirect_view), # 如果请求URL匹配成功，比如请求`http://mywebsite.com/redirect/`，就会到运行相应的视图逻辑\n",
    "    path('/redirect-success/', veiw.redirect_success_view),\n",
    "    # ... more URL patterns here\n",
    "]\n",
    "views.py：定义视图\n",
    "urls.py：定义 URL 匹配模式\n",
    "\n",
    "我们也可以重写 redirect_view(request)，这回使用 HttpResponseRedirect 去实现重定向。\n",
    "\n",
    "# 方法二\n",
    "def redirect_view(request):\n",
    "  return HttpResponseRedirect('/redirect-success/')\n",
    "如果只是跳转，没有其它的业务逻辑，可以考虑使用视图类。比如你向你的服务器请求一个 URL:http://mywebsite.com/search/xxx，服务器直接跳转到新的 URL:https://google.com/?q=xxx\n",
    "\n",
    "#urls.py\n",
    "from django.views.generic.base import RedirectView\n",
    "\n",
    "urlpatterns = [\n",
    "    path('/search/<term>/',\n",
    "         RedirectView.as_view(url='https://google.com/?q=%(term)s')),\n",
    "]\n",
    "什么情况下我们需要重定向呢？\n",
    "\n",
    "比如：\n",
    "\n",
    "当您未登录并请求需要身份验证的 URL（例如 Django admin）时，Django 会将您重定向到登录页面；\n",
    "成功登录后，Django 会将您重定向到您最初请求的 URL；\n",
    "使用 Django 管理员更改密码时，您将被重定向到指示更改成功的页面。\n",
    "下面我们看看重定向会发生什么？除了页面重新渲染。它的 response 的状态码是什么？假设我本地开发环境上运行一个 Django 应用，且支持上面定义的重定向。\n",
    "\n",
    "一般的请求所返回的：\n",
    "\n",
    "$ curl --include http://127.0.0.1:8000/hello/\n",
    "HTTP/1.1 200 OK\n",
    "Date: Sun, 01 Jul 2018 20:32:55 GMT\n",
    "Server: WSGIServer/0.2 CPython/3.6.3\n",
    "Content-Type: text/html; charset=utf-8\n",
    "X-Frame-Options: SAMEORIGIN\n",
    "Content-Length: 11\n",
    "\n",
    "Hello World\n",
    "这是重定向的返回数据，注意里面有个 Location，还有状态码是 302。其它的基本和一般的请求返回差不多。你可以像方法二一样去实例化一个 HttpResponseRedirect 对象，看看它的 status_code 和 'Location'。\n",
    "\n",
    "curl --include http://127.0.0.1:8000/redirect/\n",
    "HTTP/1.1 302 Found\n",
    "Date: Sun, 01 Jul 2018 20:35:34 GMT\n",
    "Server: WSGIServer/0.2 CPython/3.6.3\n",
    "Content-Type: text/html; charset=utf-8\n",
    "Location: /redirect-success/\n",
    "X-Frame-Options: SAMEORIGIN\n",
    "Content-Length: 0\n",
    "由此我们知道，302 用来做临时跳转，比如未登陆的用户访问用户中心重定向到登录页面。表示旧地址 A 的资源还在（仍然可以访问），这个重定向只是临时地从旧地址 A 跳转到地址 B。\n",
    "\n",
    "另外，状态码 301 也是重定向的一种返回状态码，它和上面的 302 有什么区别？\n",
    "\n",
    "301 比较常用的场景是使用域名跳转。比如，我们访问 http://baidu.com 会跳转到 https://www.baidu.com 表示旧地址 A 的资源已经被永久地移除了。\n",
    "curl --include https://baidu.com\n",
    "HTTP/1.1 302 Moved Temporarily\n",
    "Server: bfe/1.0.8.18\n",
    "Date: Wed, 22 Jan 2020 02:58:38 GMT\n",
    "Content-Type: text/html\n",
    "Content-Length: 161\n",
    "Connection: keep-alive\n",
    "Location: http://www.baidu.com/\n",
    "预览\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
